<!DOCTYPE html>
<html lang="zhCN">

<head>
    <title>羊了个羊3D地图</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <style>
        body {
            background-color: #ecf0e7;
            color: #000;
            overflow: hidden;
            font-family: Monospace;
            font-size: 33px;
            line-height: 54px;
            overscroll-behavior: none;
        }

        a {
            color: #f00;
            text-decoration: none;
        }

        a:hover {
            text-decoration: underline;
        }

        * {
            margin: 0;
        }

        #info {
            position: absolute;
            top: 0px;
            width: 100%;
            padding: 10px;
            box-sizing: border-box;
            text-align: center;
            -moz-user-select: none;
            -webkit-user-select: none;
            -ms-user-select: none;
            user-select: none;
            font-size: 20px;
            /* 调整字体大小 */
        }
    </style>
</head>

<body>
    <div id="info">
        <a id="undo" href="javascript:void(0)">【撤销移除】</a>
        <a id="auto_solve" href="javascript:void(0)" aria-label="自动解答"></a>
        <a id="single_step_solve" href="javascript:void(0)" aria-label="单步解答"></a>
    </div>

    <!-- Import maps polyfill -->
    <!-- Remove this when import maps will be widely supported -->
    <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

    <script type="importmap">
            {
                "imports": {
                    "three": "https://unpkg.com/three@0.145.0/build/three.module.js",
                    "OrbitControls": "https://unpkg.com/three@0.145.0/examples/jsm/controls/OrbitControls.js"
                }
            }
        </script>

    <script type="module">

        import * as THREE from 'three';

        import { OrbitControls } from 'OrbitControls';

        let camera, controls, scene, renderer;
        const raycaster = new THREE.Raycaster();
        const mouse = new THREE.Vector2();
        const removed_blocks = [];
        var map_data;

        // 显示解答步骤的变量
        var block_objects = {}
        var solve_index = 0;
        var highlight_mesh = null;
        var solve_interval = null;

        var material_blocks = [];
        var mask_material_blocks = [];
        var material_side;

        // 卡槽
        var slots = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        var counter = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        var slot_objects = [];
        var slot_blocks_data = [];
        var out_appear = false;
        var out_objects = {};
        var out_virtual_object;
        var out2_appear = false;
        var out2_objects = {};
        var out2_virtual_object;

        init();
        //render(); // remove when using next line for animation loop (requestAnimationFrame)
        animate();

        bindEvent();

        function shallowClone(obj) {
            var objClone = Array.isArray(obj) ? [] : {};
            if (obj && typeof (obj) == "object" && obj != null) {
                for (let key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        objClone[key] = obj[key];
                    }
                }
            }
            return objClone;
        }

        function init() {
            scene = new THREE.Scene();
            const textureLoader = new THREE.TextureLoader();

            // 加载纹理时使用回调确保图片加载完成
            const backgroundTexture = textureLoader.load('images/背景草地.png', (texture) => {
                texture.minFilter = THREE.LinearFilter; // 禁用mipmap
                texture.generateMipmaps = false;

                // 重新计算尺寸参数
                const canvasWidth = window.innerWidth;
                const canvasHeight = window.innerHeight;
                const imageAspect = 450 / 800;
                const viewAspect = canvasWidth / canvasHeight;

                if (viewAspect > imageAspect) { // 画布更宽
                    texture.repeat.set(viewAspect / imageAspect, 1);
                    texture.offset.set((1 - viewAspect / imageAspect) / 2, 0);
                } else { // 画布更高
                    texture.repeat.set(1, imageAspect / viewAspect);
                    texture.offset.set(0, (1 - imageAspect / viewAspect) / 2);
                }

                // 禁用重复
                texture.wrapS = THREE.ClampToEdgeWrapping;
                texture.wrapT = THREE.ClampToEdgeWrapping;
                texture.needsUpdate = true;
            }, undefined, (error) => {
                showAlert("加载背景纹理失败: " + error.message);
            });

            scene.background = backgroundTexture;

            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.setSize(window.innerWidth, window.innerHeight);
            document.body.appendChild(renderer.domElement);

            //camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 1, 2000 );
            camera = new THREE.OrthographicCamera(window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 2000);
            camera.zoom = 6;
            camera.setViewOffset(window.innerWidth, window.innerHeight, 0, -120, window.innerWidth, window.innerHeight);//相机设置中的视口偏移
            camera.position.set(0, 300, 0);

            // controls

            controls = new OrbitControls(camera, renderer.domElement);
            controls.listenToKeyEvents(window); // optional

            //controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop)

            controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
            controls.dampingFactor = 0.05;

            controls.screenSpacePanning = false;

            controls.minDistance = 100;
            controls.maxDistance = 500;
            controls.maxPolarAngle = Math.PI / 2;

            // 加载地图数据
            var url = "./shuffled_map.json"
            var request = new XMLHttpRequest();
            request.open("get", url);
            request.send(null);
            request.onload = function () {
                if (request.status == 200) {
                    try {
                        map_data = JSON.parse(request.responseText);
                        showAlert("不使用洗牌道具");
                        render_map();
                    } catch (e) {
                        showAlert("使用洗牌道具");
                        loadFallbackMap();
                    }
                } else {
                    showAlert("使用洗牌道具");
                    loadFallbackMap();
                }
            }

            function loadFallbackMap() {
                var fallbackUrl = "./shuffled_map1.json";
                var fallbackRequest = new XMLHttpRequest();
                fallbackRequest.open("get", fallbackUrl);
                fallbackRequest.send(null);
                fallbackRequest.onload = function () {
                    if (fallbackRequest.status == 200) {
                        try {
                            map_data = JSON.parse(fallbackRequest.responseText);
                            render_map();
                        } catch (e) {
                            const errorMessage = `解析备用JSON失败: ${e.message}`;
                            showAlert(errorMessage);
                        }
                    } else {
                        const statusMessages = {
                            400: '错误请求',
                            401: '未授权访问',
                            403: '访问被禁止',
                            404: '资源未找到',
                            500: '服务器内部错误',
                            503: '服务不可用',
                            default: '未知网络错误'
                        };
                        const message = statusMessages[fallbackRequest.status] || statusMessages.default;
                        showAlert(`获取备用地图数据失败: ${message}（状态码 ${fallbackRequest.status}）`);
                    }
                }
            }
        }

        function render_map() {
            // 新增详细数据结构检查
            if (!map_data) {
                showAlert("地图数据未正确加载，请检查数据源是否正确。");
                return;
            }

            // 检查核心字段
            if (!map_data.levelData) {
                showAlert("地图数据缺少必需的 'levelData' 字段，请检查JSON结构。");
                return;
            }

            // 检查辅助字段
            if (!map_data.out || !Array.isArray(map_data.out)) {
                showAlert("地图数据缺少或格式错误的 'out' 字段，请检查JSON结构。");
                return;
            }
            if (!map_data.out2 || !Array.isArray(map_data.out2)) {
                showAlert("地图数据缺少或格式错误的 'out2' 字段，请检查JSON结构。");
                return;
            }
            if (!map_data.ids || !Array.isArray(map_data.ids)) {
                showAlert("地图数据缺少或格式错误的 'ids' 字段，请检查JSON结构。");
                return;
            }

            // 新增数据完整性验证
            const level_data = map_data.levelData;
            for (const layer in level_data) {
                const block_datas = level_data[layer];
                if (!Array.isArray(block_datas)) {
                    showAlert(`层 ${layer} 的数据格式错误，应为数组`);
                    return;
                }
                for (let j = 0; j < block_datas.length; j++) {
                    const block_data = block_datas[j];
                    if (!block_data || typeof block_data !== 'object') {
                        showAlert(`层 ${layer} 的第 ${j} 个块数据无效`);
                        return;
                    }
                    /*                    if (typeof block_data.rowNum !== 'number' ||
                                           typeof block_data.rolNum !== 'number' ||
                                           typeof block_data.type !== 'number') {
                                           showAlert(`层 ${layer} 的第 ${j} 个块数据缺少必要属性`);
                                           return;
                                       } */
                }
            }
            if (!map_data.out2 || !Array.isArray(map_data.out2)) {
                showAlert("地图数据缺少或格式错误的 'out2' 字段，请检查JSON结构。");
                return;
            }
            if (!map_data.ids || !Array.isArray(map_data.ids)) {
                showAlert("地图数据缺少或格式错误的 'ids' 字段，请检查JSON结构。");
                return;
            }

            // 创建日期显示元素
            const dateDiv = document.createElement('div');
            dateDiv.id = 'dateDisplay';
            dateDiv.style.position = 'absolute';
            dateDiv.style.top = '58px'; // 调整位置更靠下
            dateDiv.style.left = '50%';
            dateDiv.style.transform = 'translateX(-50%)';
            dateDiv.style.color = '#ffffff'; // 白色文字
            dateDiv.style.fontSize = '18px'; // 调小字体
            dateDiv.style.fontFamily = 'Arial, sans-serif';
            dateDiv.style.zIndex = '1000';
            dateDiv.style.padding = '2px 6px'; // 进一步减少内边距
            dateDiv.style.backgroundColor = '#000000'; // 纯黑背景，不透明
            dateDiv.style.borderRadius = '2px'; // 调小圆角
            dateDiv.style.whiteSpace = 'nowrap'; // 防止文字换行
            dateDiv.style.lineHeight = '1.2'; // 调整行高
            document.body.appendChild(dateDiv);

            // 更新日期显示
            function updateDate() {
                const now = new Date();
                const month = now.getMonth() + 1;
                const day = now.getDate();
                dateDiv.textContent = `- ${month}月${day}日 -`; // 按照示例添加前后短横线
            }

            // 初始更新
            updateDate();
            // 每天更新一次
            setInterval(updateDate, 86400000);
            // 构建地图遮挡关系
            var mask_data = [];
            for (var row = 0; row < 80; row++) {
                var rows = [];
                for (var col = 0; col < 64; col++) {
                    rows.push(null);
                }
                mask_data.push(rows);
            }
            const layers = Object.keys(level_data);
            layers.sort(function (a, b) {
                return parseInt(a) - parseInt(b);
            })
            for (let i = 0; i < layers.length; i++) {
                var layer = layers[i];
                var block_datas = level_data[layer];
                if (!block_datas) continue; // 新增空值检查
                for (let j = 0; j < block_datas.length; j++) {
                    var block_data = block_datas[j];
                    if (!block_data) continue; // 新增空值检查
                    block_data.rowNum = block_data.rowNum || 0;
                    block_data.rolNum = block_data.rolNum || 0;
                    counter[block_data.type] += 1;
                    block_data.pre_blocks = [];     // 遮挡住的方块
                    block_data.next_blocks = [];    // 被遮挡的方块
                    block_data.pre_slot_blocks_data = [];  // 取走方块前的slot状态
                    // 取走方块方法
                    block_data.take_away = function () {
                        for (var i = 0; i < this.pre_blocks.length; i++) {
                            var pre_block = this.pre_blocks[i];
                            pre_block.next_blocks.pop(this);
                            update_block_material(block_objects[pre_block.id]);
                        }
                        // 维护slot
                        this.pre_slot_blocks_data = shallowClone(slot_blocks_data);
                        add_block_to_slots(this);
                        counter[this.type] -= 1;
                        slots[this.type] += 1;
                        if (slots[this.type] >= 3) {
                            slots[this.type] = 0;
                        }
                        update_slots();
                    }
                    // 放回方块方法
                    block_data.put_back = function () {
                        for (var i = 0; i < this.pre_blocks.length; i++) {
                            var pre_block = this.pre_blocks[i];
                            pre_block.next_blocks.push(this);
                            update_block_material(block_objects[pre_block.id]);
                        }
                        // 维护slot
                        slot_blocks_data = shallowClone(this.pre_slot_blocks_data);
                        counter[this.type] += 1;
                        slots[this.type] -= 1;
                        if (slots[this.type] < 0) {
                            slots[this.type] = 2;
                        }
                        update_slots();
                    }
                    // 是否可以移除
                    block_data.removable = function () {
                        return this.next_blocks.length == 0;
                    }
                    // 找出被当前方块遮挡住的方块
                    var pre_blocks = [];
                    for (var col = block_data.rolNum; col < block_data.rolNum + 8; col++) {
                        for (var row = block_data.rowNum; row < block_data.rowNum + 8; row++) {
                            var pre_block = mask_data[row][col];
                            if (pre_block) {
                                pre_blocks.push(pre_block);
                            }
                            mask_data[row][col] = block_data;
                        }
                    }
                    // 构建方块的遮挡关系
                    for (var k = 0; k < pre_blocks.length; k++) {
                        var pre_block = pre_blocks[k];
                        if (block_data.pre_blocks.indexOf(pre_block) < 0) {
                            block_data.pre_blocks.push(pre_block);
                        }
                        if (pre_block.next_blocks.indexOf(block_data) < 0) {
                            pre_block.next_blocks.push(block_data);
                        }
                    }
                }
            }
            // console.log(mask_data);

            // 方块图案
            const textureLoader = new THREE.TextureLoader();
            material_side = new THREE.MeshLambertMaterial({
                map: textureLoader.load('images/side.png'),
            })
            for (let i = 0; i <= 16; i++) {
                material_blocks.push(new THREE.MeshLambertMaterial({
                    map: textureLoader.load(
                        `images/${i}.png`,
                        undefined,
                        undefined,
                        (error) => {
                            showAlert(`加载纹理 ${i}.png 失败: ${error.message}`);
                        }
                    )
                }));
            }

            // 创建方块
            var geometry = new THREE.BoxGeometry(8, 2, 8);
            for (let i = 0; i < layers.length; i++) {
                var layer = layers[i];
                var block_datas = level_data[layer];
                for (let j = 0; j < block_datas.length; j++) {
                    var block_data = block_datas[j];
                    print_block_info(block_data, false);


                    // 方块
                    const block_object = new THREE.Mesh(geometry, null);
                    block_object.position.x = block_data['rolNum'] - 28;
                    block_object.position.y = (block_data['layerNum'] - 1) * 3.5;
                    block_object.position.z = block_data['rowNum'] - 36 - 20;
                    block_object.updateMatrix();
                    block_object.matrixAutoUpdate = false;
                    block_object.block_data = block_data;
                    block_object.need_handle_scene = true;
                    scene.add(block_object);
                    block_objects[block_data['id']] = block_object;
                    update_block_material(block_object);

                    // 遮挡阴影
                    const mask_geometry = new THREE.BoxGeometry(7.999, 1.999, 7.999);
                    const mask_material = new THREE.MeshBasicMaterial({ color: 0x000000, opacity: 0.5, transparent: true });
                    const mask_object = new THREE.Mesh(mask_geometry, mask_material);
                    mask_object.position.y = 0.001;
                    mask_object.is_mask = true;
                    block_object.mask_object = mask_object;
                    update_block_material(block_object);
                }
            }

            // 创建出现在道具中的几张牌
            const out_ids = map_data['out'];
            for (let i = 0; i < out_ids.length; i++) {
                var block_id = out_ids[i];
                var org_block_object = block_objects[block_id];
                if (!org_block_object) {
                    console.error('无效的out_id:', block_id);
                    continue; // 新增无效ID跳过机制
                }
                const new_block_object = new THREE.Mesh(geometry, null);
                new_block_object.position.x = 8 * i - 8;
                new_block_object.position.y = 0;
                new_block_object.position.z = 20;
                new_block_object.updateMatrix();
                new_block_object.matrixAutoUpdate = false;
                new_block_object.block_data = shallowClone(org_block_object.block_data);
                new_block_object.block_data.pre_blocks = [];
                new_block_object.block_data.next_blocks = [];
                new_block_object.block_data.pre_slot_blocks_data = [];  // 取走方块前的slot状态
                new_block_object.block_data.removable = function () {
                    return true;
                }
                new_block_object.block_data.take_away = function () {
                    scene.remove(new_block_object);
                    // 维护slot
                    this.pre_slot_blocks_data = shallowClone(slot_blocks_data);
                    add_block_to_slots(this);
                    slots[this.type] += 1;
                    if (slots[this.type] >= 3) {
                        slots[this.type] = 0;
                    }
                    update_slots();
                }
                new_block_object.block_data.put_back = function () {
                    scene.add(new_block_object);
                    // 维护slot
                    slot_blocks_data = shallowClone(this.pre_slot_blocks_data);
                    slots[this.type] -= 1;
                    if (slots[this.type] < 0) {
                        slots[this.type] = 2;
                    }
                    update_slots();
                }
                new_block_object.need_handle_scene = false;
                out_objects[block_id] = new_block_object;
                update_block_material(new_block_object);
            }

            // 创建out2道具时的id有效性检查
            const out2_ids = map_data['out2'];
            for (let i = 0; i < out2_ids.length; i++) {
                var block_id = out2_ids[i];
                var org_block_object = block_objects[block_id];
                if (!org_block_object) {
                    console.error('无效的out2_id:', block_id);
                    continue; // 新增无效ID跳过机制
                }
                const new_block_object = new THREE.Mesh(geometry, null);
                new_block_object.position.x = 8 * i - 8;
                new_block_object.position.y = 3.5;
                new_block_object.position.z = 20;
                new_block_object.updateMatrix();
                new_block_object.matrixAutoUpdate = false;
                new_block_object.block_data = shallowClone(org_block_object.block_data);
                new_block_object.block_data.pre_blocks = [];
                new_block_object.block_data.next_blocks = [];
                new_block_object.block_data.pre_slot_blocks_data = [];  // 取走方块前的slot状态
                new_block_object.block_data.removable = function () {
                    return true;
                }
                new_block_object.block_data.take_away = function () {
                    scene.remove(new_block_object);
                    // 维护slot
                    this.pre_slot_blocks_data = shallowClone(slot_blocks_data);
                    add_block_to_slots(this);
                    slots[this.type] += 1;
                    if (slots[this.type] >= 3) {
                        slots[this.type] = 0;
                    }
                    update_slots();
                }
                new_block_object.block_data.put_back = function () {
                    scene.add(new_block_object);
                    // 维护slot
                    slot_blocks_data = shallowClone(this.pre_slot_blocks_data);
                    slots[this.type] -= 1;
                    if (slots[this.type] < 0) {
                        slots[this.type] = 2;
                    }
                    update_slots();
                }
                new_block_object.need_handle_scene = false;
                out2_objects[block_id] = new_block_object;
                update_block_material(new_block_object);
            }

            // 两个虚拟的道具方块
            out_virtual_object = {
                name: "out",
                need_handle_scene: false,
                block_data: {
                    type: 0,
                    pre_blocks: [],
                    next_blocks: [],
                    pre_slot_blocks_data: [],
                    is_virtual: true,
                    // 使用道具的方法
                    take_away: function () {
                        out_appear = true;
                        // 维护slot
                        this.pre_slot_blocks_data = shallowClone(slot_blocks_data);
                        for (let key in out_objects) {
                            const block_object = out_objects[key];
                            scene.add(block_object);
                            remove_block_from_slots(block_object.block_data);
                            const block_type = block_object.block_data.type;
                            slots[block_type] -= 1;
                            if (slots[block_type] < 0) {
                                slots[block_type] = 2;
                            }
                        }
                        update_slots();
                    },
                    // 回撤道具的方法
                    put_back: function () {
                        // 维护slot
                        slot_blocks_data = shallowClone(this.pre_slot_blocks_data);
                        for (let key in out_objects) {
                            const block_object = out_objects[key];
                            scene.remove(block_object);
                            const block_type = block_object.block_data.type;
                            slots[block_type] += 1;
                            if (slots[block_type] >= 3) {
                                slots[block_type] = 0;
                            }
                        }
                        update_slots();
                        out_appear = false;
                    }
                }
            };
            out2_virtual_object = {
                name: "out2",
                need_handle_scene: false,
                block_data: {
                    type: 0,
                    pre_blocks: [],
                    next_blocks: [],
                    pre_slot_blocks_data: [],
                    is_virtual: true,
                    // 使用道具的方法
                    take_away: function () {
                        out2_appear = true;
                        // 维护slot
                        this.pre_slot_blocks_data = shallowClone(slot_blocks_data);
                        for (let key in out2_objects) {
                            const block_object = out2_objects[key];
                            scene.add(block_object);
                            remove_block_from_slots(block_object.block_data);
                            const block_type = block_object.block_data.type;
                            slots[block_type] -= 1;
                            if (slots[block_type] < 0) {
                                slots[block_type] = 2;
                            }
                        }
                        update_slots();
                    },
                    // 回撤道具的方法
                    put_back: function () {
                        // 维护slot
                        slot_blocks_data = shallowClone(this.pre_slot_blocks_data);
                        for (let key in out2_objects) {
                            const block_object = out2_objects[key];
                            scene.remove(block_object);
                            const block_type = block_object.block_data.type;
                            slots[block_type] += 1;
                            if (slots[block_type] >= 3) {
                                slots[block_type] = 0;
                            }
                        }
                        update_slots();
                        out2_appear = false;
                    }
                }
            };

            // 添加卡槽背景图片
            // 删除 const textureLoader = new THREE.TextureLoader(); 这行
            const backgroundTexture = textureLoader.load('images/消除区域.png'); // 替换为你的本地图片路径
            const backgroundMaterial = new THREE.MeshBasicMaterial({
                map: backgroundTexture,
                transparent: true
            });
            const backgroundGeometry = new THREE.PlaneGeometry(60, 14); // 根据图片尺寸调整
            const backgroundPlane = new THREE.Mesh(backgroundGeometry, backgroundMaterial);
            backgroundPlane.position.set(0, -1, 28); // 调整位置使其在卡槽下方
            backgroundPlane.rotation.x = -Math.PI / 2; // 旋转使其水平
            scene.add(backgroundPlane);

            // 卡槽方块
            for (let i = 0; i < 7; i++) {
                const block_object = new THREE.Mesh(geometry, null);
                block_object.position.x = 8 * i - 24;
                block_object.position.y = 0;
                block_object.position.z = 28;
                block_object.updateMatrix();
                block_object.matrixAutoUpdate = false;
                scene.add(block_object);
                slot_objects.push(block_object);
                var block_data = {
                    "type": 0,
                    "pre_blocks": [],
                    "next_blocks": [],
                    "is_slot": true
                }
                block_data.removable = function () {
                    return true;
                }
                block_object.block_data = block_data;

                // 初始设置为完全透明
                const materials = [
                    new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 }), // 底部
                    new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 }), // 顶部
                    new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 }), // 前面
                    new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 }), // 后面
                    new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 }), // 左面
                    new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 })  // 右面
                ];
                block_object.material = materials;
            }
            // 如果有解题步骤
            if (has_solve_steps()) {

                // 高亮指示器
                geometry = new THREE.BoxGeometry(8, 2, 8);
                const material = new THREE.MeshBasicMaterial({ color: 0xff0000, opacity: 0.6, transparent: true })
                highlight_mesh = new THREE.Mesh(geometry, material);
                highlight_mesh.position.x = 1000;
                highlight_mesh.position.y = 1000;
                highlight_mesh.position.z = 1000;
                highlight_mesh.updateMatrix();
                highlight_mesh.matrixAutoUpdate = false;
                scene.add(highlight_mesh);
                update_highlight_mesh();

                // 显示解题按钮
                document.getElementById('auto_solve').text = "【自动解答】";
                document.getElementById('single_step_solve').text = "【单步解答】";
            }

            // lights
            const dirLight0 = new THREE.DirectionalLight(0xffffff);
            dirLight0.position.set(0, 100, 0);
            scene.add(dirLight0);

            const dirLight1 = new THREE.DirectionalLight(0xffffff);
            dirLight1.position.set(1, 0, 1);
            scene.add(dirLight1);

            const dirLight2 = new THREE.DirectionalLight(0xffffff);
            dirLight2.position.set(- 1, - 1, - 1);
            scene.add(dirLight2);

            const ambientLight = new THREE.AmbientLight(0x222222);
            scene.add(ambientLight);

            window.addEventListener('resize', onWindowResize);

            document.addEventListener('click', onMouseClick);
        }

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        function onMouseClick(event) {

            //将鼠标点击位置的屏幕坐标转换成threejs中的标准坐标
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            mouse.y = -((event.clientY / window.innerHeight) * 2 - 1);

            // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
            raycaster.setFromCamera(mouse, camera);

            // 获取raycaster直线和所有模型相交的数组集合
            var intersects = raycaster.intersectObjects(scene.children);
            //console.log(intersects);

            for (var i = 0; i < intersects.length; i++) {
                var object = intersects[i].object;
                if (object.is_mask) {
                    continue;
                }
                var block_data = object.block_data;
                if (!block_data.removable()) {
                    return;
                }
                if (block_data.is_slot) {
                    return;
                }
                if (has_solve_steps()) {
                    alert("有解的情况禁止手动移除方块，不然把解答途中的方块移除掉会导致局面出现问题。");
                    return;
                }
                if (is_game_over()) {
                    return;
                }
                print_block_info(block_data, true);
                removed_blocks.push(object);
                scene.remove(object);
                block_data.take_away();
                return;
            }
        }


        function animate() {
            requestAnimationFrame(animate);
            controls.update(); // only required if controls.enableDamping = true, or if controls.autoRotate = true
            render();
        }

        function render() {
            renderer.render(scene, camera);
        }

        // 打印方块信息
        function print_block_info(block_data, is_remove) {
            if (!block_data || typeof block_data !== 'object') { // 新增严格校验
                console.error('block_data无效或类型错误，跳过打印:', block_data);
                return;
            }

            var type2name = {
                1: "青草",
                2: "胡萝卜",
                3: "玉米",
                4: "树桩",
                5: "草叉",
                6: "白菜",
                7: "羊毛",
                8: "刷子",
                9: "剪刀",
                10: "奶瓶",
                11: "水桶",
                12: "手套",
                13: "铃铛",
                14: "火堆",
                15: "毛球",
                16: "干草"
            }

            var layer = block_data['layerNum'];
            var x = block_data['rolNum'];
            var y = block_data['rowNum'];
            var type = block_data['type'];
            var name = type2name[type];
            var info = `层数:${layer}, 坐标:(${x}, ${y}), 类型:${type}(${name})`
            if (is_remove) {
                info = "移除方块 >> " + info;
            }
            console.log(info);
        }

        // 游戏是否结束
        function is_game_over() {
            var sum = 0;
            for (var i = 0; i < slots.length; i++) {
                sum += slots[i];
            }
            return sum >= 8;
        }

        // 更新方块图案
        function update_block_material(block_object) {
            if (!block_object || !block_object.block_data) { // 新增严格校验
                console.error('block_data未定义，跳过材质更新:', block_object);
                return;
            }
            // 更新图案
            var block_data = block_object.block_data;
            var material = material_blocks[block_data.type];
            var materials = block_object.material;
            if (materials == null) {
                materials = [material_side, material_side, material, material_side, material_side, material_side];
            } else {
                materials[2] = material;
            }
            block_object.material = materials;


            // 更新遮挡阴影
            if (block_data.removable()) {
                block_object.remove(block_object.mask_object);
            } else {
                block_object.add(block_object.mask_object);
            }
        }

        // 添加卡槽方框
        function add_block_to_slots(block_data) {
            let cnt = 0;
            let idx = -1;
            for (let i = 0; i < slot_blocks_data.length; i++) {
                if (slot_blocks_data[i].type == block_data.type) {
                    cnt++;
                    if (idx < 0) {
                        idx = i;
                    }
                }
            }
            if (cnt == 0) {
                slot_blocks_data.push(block_data);
            }
            else if (cnt == 1) {
                slot_blocks_data.splice(idx + 1, 0, block_data);
            }
            else if (cnt == 2) {
                slot_blocks_data.splice(idx, 2);
            }
        }

        // 移除卡槽方框
        function remove_block_from_slots(block_data) {
            for (let i = 0; i < slot_blocks_data.length; i++) {
                if (slot_blocks_data[i].id == block_data.id) {
                    slot_blocks_data.splice(i, 1);
                    return;
                }
            }
        }

        // 更新卡槽方块
        function update_slots() {
            for (let i = 0; i < 7; i++) {
                var object = slot_objects[i];
                object.block_data.type = 0;

                // 如果当前格子没有卡片，保持透明
                if (i >= slot_blocks_data.length) {
                    const materials = [
                        new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 }), // 底部
                        new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 }), // 顶部
                        new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 }), // 前面
                        new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 }), // 后面
                        new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 }), // 左面
                        new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 })  // 右面
                    ];
                    object.material = materials;
                    continue;
                }

                // 如果有卡片，显示格子
                object.block_data.type = slot_blocks_data[i].type;
                const materials = [
                    new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.3 }), // 底部
                    new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.3 }), // 顶部
                    material_blocks[slot_blocks_data[i].type], // 前面
                    new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.3 }), // 后面
                    new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.3 }), // 左面
                    new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.3 })  // 右面
                ];
                object.material = materials;
            }

            if (slot_blocks_data.length >= 7) {
                showAlert("游戏结束，卡槽中的牌数量达到或超过7张。");
                if (is_game_over()) {
                    console.log("游戏结束！");
                }
            }
        }

        // 是否包含解题步骤
        function has_solve_steps() {
            if (map_data['ids'] == null) {
                return false;
            }
            if (map_data['ids'].length == 0) {
                return false;
            }
            return true;
        }

        // 更新高亮方块位置
        function update_highlight_mesh() {
            if (solve_index < map_data['ids'].length) {
                var block_id = map_data['ids'][solve_index];
                // 新增：跳过 null 值
                if (block_id === null) {
                    highlight_mesh.position.x = 1000;
                    highlight_mesh.position.y = 1000;
                    highlight_mesh.position.z = 1000;
                    highlight_mesh.updateMatrix();
                    return;
                }
                var block_object;
                if (block_id == "out" || block_id == "out2") {
                    highlight_mesh.position.x = 1000;
                    highlight_mesh.position.y = 1000;
                    highlight_mesh.position.z = 1000;
                    highlight_mesh.updateMatrix();
                    return;
                }
                if (out_appear && out_objects[block_id]) {
                    block_object = out_objects[block_id];
                }
                else if (out2_appear && out2_objects[block_id]) {
                    block_object = out2_objects[block_id];
                }
                else {
                    block_object = block_objects[block_id];
                }
                highlight_mesh.position.x = block_object.position.x;
                highlight_mesh.position.y = block_object.position.y;
                highlight_mesh.position.z = block_object.position.z;
            } else {
                highlight_mesh.position.x = 1000;
                highlight_mesh.position.y = 1000;
                highlight_mesh.position.z = 1000;
            }
            highlight_mesh.updateMatrix();
        }

        // 撤销移除
        function undo() {
            const object = removed_blocks.pop();
            if (object) {
                if (object.need_handle_scene)
                    scene.add(object);
                object.block_data.put_back();
                if (solve_index > 0) {
                    solve_index -= 1;
                }
                update_highlight_mesh();
            }
        }

        function auto_solve() {
            if (is_game_over()) {
                showAlert("游戏已结束，自动解答无效。");
                return;
            }
            var auto_solve_element = document.getElementById('auto_solve');
            if (solve_interval == null) {
                solve_interval = setInterval(function () {
                    if (is_game_over()) {
                        clearInterval(solve_interval);
                        solve_interval = null;
                        auto_solve_element.text = '【自动解答】';
                        showAlert("游戏已结束，自动解答停止。");
                        return;
                    }
                    single_step_solve();
                }, 100);
                auto_solve_element.text = '【停止解答】';
            } else {
                clearInterval(solve_interval);
                solve_interval = null;
                auto_solve_element.text = '【自动解答】';
            }
        }


        // 单步解答
        function single_step_solve() {
            if (map_data['ids'] == null) {
                return;
            }
            if (solve_index >= map_data['ids'].length) {
                if (is_game_over()) {
                    showAlert("游戏已结束，单步解答无效。");
                    return;
                }
            }
            var block_id = map_data['ids'][solve_index];
            // 新增：跳过 null 值
            if (block_id === null) {
                solve_index += 1; // 跳过无效的 null 值
                update_highlight_mesh();
                return;
            }
            var block_object;
            if (block_id == "out")
                block_object = out_virtual_object;
            else if (block_id == "out2")
                block_object = out2_virtual_object;
            else if (out_appear && out_objects[block_id])
                block_object = out_objects[block_id];
            else if (out2_appear && out2_objects[block_id])
                block_object = out2_objects[block_id];
            else
                block_object = block_objects[block_id];
            if (!block_object || !block_object.block_data) { // 新增对象有效性检查
                console.error('无效的block_object:', block_id);
                return;
            }
            if (block_object.need_handle_scene)
                scene.remove(block_object);
            removed_blocks.push(block_object);
            print_block_info(block_object.block_data, true);
            block_object.block_data.take_away();
            solve_index += 1;
            update_highlight_mesh();
        }

        function bindEvent() {
            document.getElementById('undo').onclick = undo;
            document.getElementById('auto_solve').onclick = auto_solve;
            document.getElementById('single_step_solve').onclick = single_step_solve;
        }

        function showAlert(message) {
            var alertBox = document.createElement('div');
            alertBox.style.position = 'fixed';
            alertBox.style.top = '20px';
            alertBox.style.left = '50%';
            alertBox.style.transform = 'translateX(-50%)';
            alertBox.style.backgroundColor = '#ff4444';
            alertBox.style.color = '#fff';
            alertBox.style.padding = '10px 20px';
            alertBox.style.borderRadius = '5px';
            alertBox.style.zIndex = '1000';
            alertBox.textContent = message;
            document.body.appendChild(alertBox);

            setTimeout(function () {
                document.body.removeChild(alertBox);
            }, 3000); // 3秒后自动关闭弹窗
        }
    </script>

</body>

</html>